Namespace & Function LookUp

네임 스페이스(Namespace)
동일한 이름의 클래스나 변수를 구분하기 위해서 네임스페이스를 사용할 수 있다.
namespace GUI{
class window;
}
namespace statistics{
class window;
}
C에서는 서로 다른 이름을 사용하여, 이름 충돌을 해결하여야 했다.
네임스페이스는 소프트웨어에서 이름을 계층적으로 구조화할 수 있게 해준다.
(네임스페이스를 사용하면, 이름 충돌을 방지하고 함수 및 클래스 이름의 접근을 정교하게 제어할 수 있다)
struct global{};
namespace c1{
struct c1c{};
namespace c2{
struct c2c{};
struct cc{
global x;
c1c y;
c2c z;
};
} // namespcae c2
} // namespace c1
내부 네임스페이스에서 정의된 이름은 바깥족 네임스페이스의 이름을 숨긴다.
하지만 네임스페이스는 스코프(블록)와 달리 네임스페이스 한정(Namespace Qualification)으로
이름을 계속 참조할 수 있다.
struct same{};
namespace c1{
struct same{};
namespace c2{
struct same{};
struct csame{
::same x; //
c1::same y; // c1
same z; // c1::c2::same
};
}
}
네임 스페이스 숨겨짐
struct same{};
namespace c1{
struct same{};
namespace c2{
struct same{};
namespace c1{} // ::c1
struct csame{
::same x;
c1::same y; // error; c1::c2::c1::same
same z;
};
}
}
자주 사용하는 클래스나 함수의 이름은 using을 사용해서 가져올 수 있다.
void fun(...){
using c1::c2::cc;
cc x;
}
함수 내부에서 using을 사용하면, 해당 스코프 안에서만 유효하다.

using namespace를 통해 네임스페이스 전체를 가져올 수 있다.
void fun(...){
using namespace c1::c2;
cc x;
}
using은 함수나 다른 네임스페이스 내에서는 동작하지만, 클래스 스코프에서는 동작하지 않는다.

namespace이름이 너무 길 경우, 별칭을 이용할 수 있다.
Namespace Alias(네임스페이스 별칭)
namespace lname=long_namespace_name;
namespace nested=long_namespace_name::yet_another_name::nested;
인수 종속 룩업(Argument-Dependent Lookup, ADL)
함수 이름의 검색은 네임스페이스로 확장되지만, 각 부모의 네임스페이스로는 확장되지 않는다.
namespace rocketscience{
struct matrix{};
void initialize(matrix& A){ /* ... */ }
matrix operator+(const matrix& A, const matrix& B){
matrix C;
initialize(C); //
add(A, B, C);
return C;
}
}
int main(void){
rocketscience::matrix A, B, C, D;
rocketscience::initialize(B); //
initialize(C); // ADL
chez_herbert::matrix E, F, G;
rocketscience::initialize(E); //
initialize(C); // error:
}
위와 같이 같은 네임스페이스(부모 스페이스) 내에서는 rocketscience:: 한정자를 사용하지 않아도 된다.

연산자와 또한 ADL의 적용을 받는다.
A=rocketscience::operator+(rocketscience::operator+(B, C), D);
//
A=B+C+D; // .
std::operator<<(chez_herbert::operator<<(rocketscience::operator<<(chez_herbert::operator<<(rocketscience::operator<<(std::cout, A), E), B), F), std::endl);
//
std::cout<<A<<E<<B<<F<<std::endl; // .
// , std:: , operator<<
ADL을 여러 네임스페이스에 분산되어 있을 경우, 올바른 함수 템플릿 오버로드를 선택하는데 사용
namespace rocketscience{
namespace mat{
struct sparse_matrix{};
struct dense_matrix{};
struct uber_matrix{};
template <typename Matrix>
double one_norm(const Matrix& A){ ... }
}
namespace vec{
struct sparse_matrix{};
struct dense_matrix{};
struct uber_matrix{};
template <typename Vector>
double one_norm(const Vector& x){ ... }
}
}
인자가 여러개인 함수를 사용할 때, 매개변수 타입이 서로 다른 네임스페이스에서 비롯된 경우 모호할
가능성이 더 커진다.
namespace rocketscience{
namespace mat{
...
template <typename Scalar, typename Matrix>
Matrix operator*(const Scalar& a, const Matrix& A){ ... }
}
namespace vec{
...
template <typename Scalr, typename Vector>
Vector operator*(const Scalar& a, const Vector& x){ ... }
template <typename Matrix, typename Vector>
Vector operator*(const Matrix& A, const Vector& x){ ... }
}
}
int main(int argc, char* argv[]){
rocketscience::mat::uber_matrix A;
rocketscience::vec::uber_matrix x, y;
y=A*x;
// x rocketscience::vec , A rocketscience::mat
// operator*
//
}
어떤 함수 오버로드를 호출하는지는 아래의 규칙에 따라 다르다.
- 네임스페이스 중첩 및 한정
- 이름 숨김
- ADL
- 오버로드 판별
네임스페이스 한정 또는 ADL
template <typename T>
inline void swap(T& x, T& y){
T tmp(x); x=y; y=tmp;
}
표준 라이브러리의 swap 함수 템플릿이다.
위 함수는 복사 생성자와 복사 할당 연산자를 사용하는 모든 타입에서 동작한다.
하지만, 위와 같이 코드를 구성할 경우 큰 데이터를 복사하는 경우(x, y가 각각 1GB인 경우)
총 3GB의 데이터를 복사해야 한다.
template <typename Value>
class vector{
...
friend inline void swap(vector& x, vector& y){
std::swap(x.my_size, y.my_size); std::swap(x.data, y.data);
}
private:
unsigned my_size;
Value* data;
};
template <typename T, typename U>
inline void some_function(T& x, T& y, const U& z, int i){
using std::swap;
...
::swap(x, y); // ADL .
...
}
위와 같이 vector 클래스의 멤버가 my_size, data 포인터인 경우
단순히 my_size를 교환하고, data 포인터를 교환하는 경우 더욱 메모리를 절약할 수 있다.

inline으로 선언한 함수는 자유함수로 friend 속성으로 외부에서 vector 클래스 private 멤버에 접근이 가능하다.

some_function에서 swap함수를 사용할 때, std::swap과 자유함수로 선언된 ::swap 모두 오버로드 후보가 된다.
인수 타입이 표준 구현보다 구체적이기 때문에 자유함수로 선언된(class에서 선언된)
swap 오버로드를 우선으로 고려한다.
C++11부터 swap 함수의 표준은 두 인수와 임시 변수 사이에서 값을 이동(move)하도록 구현되어 있다.
template <typename T>
inline void swap(T& x, T& y){
T tmp(move(x));
x=move(y);
y=move(tmp);
}